import pyvisa
import time
import csv
from datetime import datetime

# 1. 创建资源管理器并列出所有资源
rm = pyvisa.ResourceManager()
print(rm.list_resources())

# 2. 建立连接
# 使用LAN连接（Ceyear 3671G的IP地址）
with rm.open_resource('TCPIP0::192.168.1.10::inst0::INSTR') as nwa:
    # 设置超时时间（毫秒）
    nwa.timeout = 10000

    print("连接成功!")
    
    # 查询设备信息
    idn = nwa.query('*IDN?')
    print(f"设备: {idn.strip()}")

    # 3. 重置和基础配置
    print("重置仪器...")
    nwa.write('*RST')  # 重置仪器到默认状态
    time.sleep(5)      # 充分等待重置完成
    nwa.write('*CLS')  # 清除状态寄存器
    time.sleep(1)
    
    # 立即设置频率范围，防止被后续命令覆盖
    print("设置基础频率范围: 4GHz - 5GHz...")
    nwa.write('SENSe1:FREQuency:STARt 5200000000')  # 4GHz
    time.sleep(0.5)
    nwa.write('SENSe1:FREQuency:STOP 5800000000')  # 5GHz
    time.sleep(0.5)
    nwa.write('SENSe1:SWEep:POINts 201')
    time.sleep(0.5)
    
    # 检查系统状态和轨迹状态的函数
    def check_error():
        try:
            error = nwa.query('SYSTem:ERRor?')
            if not error.startswith('+0'):
                print(f"   系统错误: {error.strip()}")
                return False
            return True
        except:
            return True
    
    def check_traces():
        """检查当前是否有定义的测量轨迹"""
        print("   检查轨迹状态...")
        try:
            params = nwa.query('CALCulate:PARameter:CATalog?')
            print(f"   当前参数: {params.strip()}")
            
            if params.strip() == '""' or params.strip() == '' or 'NO CATALOG' in params.upper():
                print("   ❌ 没有定义的测量参数")
                return False
            else:
                print("   ✓ 找到已定义的参数")
                return True
        except Exception as e:
            print(f"   ⚠️ 参数查询失败: {e}")
            return False
    
    def ensure_traces():
        """确保轨迹存在，如果不存在则创建"""
        if not check_traces():
            print("   重新创建轨迹...")
            try:
                # 删除所有现有参数
                nwa.write('CALCulate:PARameter:DELete:ALL')
                time.sleep(1)
                
                # 创建S21幅度参数
                nwa.write('CALCulate1:PARameter:DEFine "S21_MAG",S21')
                time.sleep(1)
                check_error()
                
                # 创建S21相位参数
                nwa.write('CALCulate2:PARameter:DEFine "S21_PHASE",S21')
                time.sleep(1)
                check_error()
                
                # 验证创建结果
                if check_traces():
                    print("   ✓ 轨迹重建成功")
                    return True
                else:
                    print("   ❌ 轨迹重建失败")
                    return False
            except Exception as e:
                print(f"   ❌ 轨迹创建异常: {e}")
                return False
        return True
    
    print("配置基础参数...")
    
    # 4. 清除所有现有轨迹和参数（先检查后清除）
    print("清除现有轨迹...")
    check_traces()  # 检查初始状态
    
    try:
        nwa.write('CALCulate:PARameter:DELete:ALL')
        time.sleep(2)
        check_error()
        print("✓ 清除完成")
    except Exception as e:
        print(f"清除轨迹时出错: {e}")
    
    # 验证清除结果
    check_traces()
    
    # 5. 设置频率范围 4GHz 到 5GHz
    print("设置频率范围: 4GHz - 5GHz...")
    
    # 先设置基础的扫描参数
    nwa.write('SENSe1:SWEep:TYPE LINear')  # 线性扫描
    time.sleep(0.5)
    
    # 设置频率范围
    nwa.write('SENSe1:FREQuency:STARt 5200000000')  # 4GHz
    time.sleep(0.5)
    nwa.write('SENSe1:FREQuency:STOP 5800000000')  # 5GHz
    time.sleep(0.5)
    nwa.write('SENSe1:SWEep:POINts 201')
    time.sleep(0.5)
    
    # 验证频率设置
    try:
        start_freq = nwa.query('SENSe1:FREQuency:STARt?').strip()
        stop_freq = nwa.query('SENSe1:FREQuency:STOP?').strip()
        points = nwa.query('SENSe1:SWEep:POINts?').strip()
        print(f"   验证频率设置: 起始={float(start_freq)/1e9:.1f}GHz, 停止={float(stop_freq)/1e9:.1f}GHz, 点数={points}")
    except Exception as e:
        print(f"   验证失败: {e}")
    
    # 触发新的扫描设置
    nwa.write('SENSe1:SWEep:MODE CONTinuous')  # 连续扫描模式
    time.sleep(0.5)

    
    print("✓ 频率范围设置完成: 4GHz - 5GHz, 201点")
    
    # 6. 配置显示窗口
    print("配置显示窗口...")
    
    # 确保显示窗口1开启
    nwa.write('DISPlay:WINDow1:STATe ON')
    time.sleep(0.5)
    check_error()
    
    # 设置窗口布局为双轨迹显示
    nwa.write('DISPlay:WINDow1:SPLit D12')  # 上下分割显示两个轨迹
    time.sleep(0.5)
    check_error()
    
    print("✓ 显示窗口配置完成")
    
    # 7. 创建通道1的S21幅度轨迹
    print("创建轨迹1: 通道1 S21幅度...")
    
    # 确保在创建前检查轨迹状态
    ensure_traces()
    
    nwa.write('CALCulate1:PARameter:DEFine "S21_MAG",S21')
    time.sleep(1)
    check_error()
    
    nwa.write('CALCulate1:PARameter:SELect "S21_MAG"')
    time.sleep(0.5)
    check_error()
    
    nwa.write('CALCulate1:FORMat MLOGarithmic')  # 设置为对数幅度格式
    time.sleep(0.5)
    check_error()
    
    # 确保计算通道1也有正确的频率设置
    nwa.write('SENSe1:FREQuency:STARt 5200000000')  # 4GHz
    time.sleep(0.5)
    nwa.write('SENSe1:FREQuency:STOP 5800000000')  # 5GHz
    time.sleep(0.5)
    
    # 将S21幅度轨迹分配到显示窗口的轨迹1
    nwa.write('DISPlay:WINDow1:TRACe1:FEED "S21_MAG"')
    time.sleep(0.5)
    check_error()
    
    nwa.write('DISPlay:WINDow1:TRACe1:STATe ON')
    time.sleep(0.5)
    check_error()
    
    # 验证轨迹创建
    check_traces()
    print("✓ 通道1 S21幅度轨迹创建并显示完成")
    
    # 8. 创建通道1的S21相位轨迹 (使用CALCulate2避免冲突)
    print("创建轨迹2: 通道1 S21相位...")
    
    # 使用CALCulate2来创建相位轨迹，避免与幅度轨迹冲突
    nwa.write('CALCulate2:PARameter:DEFine "S21_PHASE",S21')
    time.sleep(1)
    check_error()
    
    nwa.write('CALCulate2:PARameter:SELect "S21_PHASE"')
    time.sleep(0.5)
    check_error()
    
    nwa.write('CALCulate2:FORMat PHASe')  # 设置为相位格式
    time.sleep(0.5)
    check_error()
    
    # 确保第二个计算通道也有正确的频率设置
    try:
        nwa.write('SENSe2:FREQuency:STARt 5200000000')  # 4GHz
        time.sleep(0.5)
        nwa.write('SENSe2:FREQuency:STOP 5800000000')  # 5GHz
        time.sleep(0.5)
        nwa.write('SENSe2:SWEep:POINts 201')
        time.sleep(0.5)
    except:
        # 如果SENSe2不支持，使用简化格式
        try:
            nwa.write('SENS2:FREQ:STAR 4E9')
            nwa.write('SENS2:FREQ:STOP 5E9')
            nwa.write('SENS2:SWE:POIN 201')
        except:
            pass
    
    # 尝试将相位轨迹分配到轨迹2
    try:
        nwa.write('DISPlay:WINDow1:TRACe2:FEED "S21_PHASE"')
        time.sleep(0.5)
        check_error()
        
        nwa.write('DISPlay:WINDow1:TRACe2:STATe ON')
        time.sleep(0.5)
        check_error()
        print("✓ 通道1 S21相位轨迹(轨迹2)创建并显示完成")
    except:
        print("✓ 通道1 S21相位轨迹创建完成（可能不支持双轨迹显示）")
    
    # 9. 执行测量
    print("执行测量...")
    
    # 测量前检查轨迹状态
    print("测量前轨迹检查:")
    if not ensure_traces():
        print("❌ 测量前轨迹检查失败")
        exit()
    
    nwa.write('SENSe1:SWEep:MODE CONTinuous')  # 连续扫描模式
    time.sleep(0.5)
    
    # 连续扫描模式下等待扫描稳定
    time.sleep(3)  # 等待连续扫描稳定
    
    # 检查扫描状态
    print("✓ 连续扫描模式已启动")
    
    # 刷新显示
    print("刷新显示...")
    nwa.write('DISPlay:WINDow1:TRACe1:Y:AUTO')  # 自动缩放轨迹1
    time.sleep(0.5)
    nwa.write('DISPlay:WINDow1:TRACe2:Y:AUTO')  # 自动缩放轨迹2  
    time.sleep(0.5)
    
    print("✓ 显示刷新完成")
    
    # 10. 读取数据前再次检查轨迹
    print("数据读取前轨迹检查:")
    if not ensure_traces():
        print("❌ 数据读取前轨迹检查失败")
        exit()
    
    # 11. 读取频率数据（仅使用有效的命令）
    print("读取频率数据...")
    freq_data = None
    
    # 使用测试中成功的命令
    try:
        print("   使用命令: SENSe1:X?")
        freq_data = nwa.query_ascii_values('SENSe1:X?')
        print(f"✓ 频率数据读取成功: {len(freq_data)} 点")
    except Exception as e:
        print(f"   频率数据读取失败: {e}")
        freq_data = None
    
    # 10. 循环测试 - 每5秒测试一次，输出到表格
    print("开始循环测试模式 - 每5秒测试一次")
    print("按 Ctrl+C 停止测试")
    
    # 表格标题
    print("\n" + "=" * 100)
    print(f"{'测试序号':<8} {'测试时间':<20} {'频率(GHz)':<12} {'幅度(dB)':<12} {'相位(度)':<12} {'信号质量':<15}")
    print("=" * 100)
    
    test_counter = 1
    target_freq = 5.44e9  # 5.45GHz目标频率

    # 初始化CSV文件
    csv_filename = f"test_results_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
    
    # 创建CSV文件并写入标题行
    with open(csv_filename, 'w', newline='', encoding='utf-8') as csvfile:
        fieldnames = ['测试序号', '测试时间', '频率(GHz)', '幅度(dB)', '相位(度)', '信号质量', '目标频率(GHz)']
        writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
        writer.writeheader()
    
    try:
        while True:
            # 获取当前时间
            current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            
            cursor_magnitude = None
            cursor_phase = None
            cursor_freq = None
            signal_quality = "未知"
            
            try:
                # 确保连续扫描模式
                nwa.write('SENSe1:SWEep:MODE CONTinuous')
                time.sleep(0.2)
                # 连续扫描模式下不需要INITiate命令
                time.sleep(0.5)  # 等待连续扫描稳定
                
                # 设置光标到1.5GHz并读取数据
                # 读取S21幅度
                nwa.write('CALCulate1:PARameter:SELect "S21_MAG"')
                time.sleep(0.2)
                nwa.write('CALCulate1:MARKer1:STATe ON')
                time.sleep(0.2)
                nwa.write(f'CALCulate1:MARKer1:X {target_freq}')
                time.sleep(0.2)
                
                cursor_freq = float(nwa.query('CALCulate1:MARKer1:X?'))
                
                nwa.write('CALCulate1:FORMat MLOGarithmic')
                time.sleep(0.2)
                magnitude_str = nwa.query('CALCulate1:MARKer1:Y?').strip()
                
                if ',' in magnitude_str:
                    cursor_magnitude = float(magnitude_str.split(',')[0])
                else:
                    cursor_magnitude = float(magnitude_str)
                
                # 读取S21相位
                nwa.write('CALCulate2:PARameter:SELect "S21_PHASE"')
                time.sleep(0.2)
                nwa.write('CALCulate2:MARKer1:STATe ON')
                time.sleep(0.2)
                nwa.write(f'CALCulate2:MARKer1:X {target_freq}')
                time.sleep(0.2)
                
                nwa.write('CALCulate2:FORMat PHASe')
                time.sleep(0.2)
                phase_str = nwa.query('CALCulate2:MARKer1:Y?').strip()
                
                if ',' in phase_str:
                    cursor_phase = float(phase_str.split(',')[0])
                else:
                    cursor_phase = float(phase_str)
                
                # 判断信号质量
                if cursor_magnitude is not None:
                    if abs(cursor_magnitude) < 3:
                        signal_quality = "良好"
                    elif abs(cursor_magnitude) < 10:
                        signal_quality = "中等"
                    else:
                        signal_quality = "较差"
                
            except Exception as e:
                print(f"测试{test_counter}失败: {e}")
                cursor_freq = target_freq
                cursor_magnitude = float('nan')
                cursor_phase = float('nan')
                signal_quality = "错误"
            
            # 输出到表格
            freq_ghz = cursor_freq/1e9 if cursor_freq else 0
            mag_str = f"{cursor_magnitude:.3f}" if cursor_magnitude and not str(cursor_magnitude) == 'nan' else "N/A"
            phase_str = f"{cursor_phase:.1f}" if cursor_phase and not str(cursor_phase) == 'nan' else "N/A"
            
            print(f"{test_counter:<8} {current_time:<20} {freq_ghz:<12.6f} {mag_str:<12} {phase_str:<12} {signal_quality:<15}")
            
            # 保存数据到CSV文件
            try:
                with open(csv_filename, 'a', newline='', encoding='utf-8') as csvfile:
                    fieldnames = ['测试序号', '测试时间', '频率(GHz)', '幅度(dB)', '相位(度)', '信号质量', '目标频率(GHz)']
                    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
                    
                    # 写入这次测试的数据
                    writer.writerow({
                        '测试序号': test_counter,
                        '测试时间': current_time,
                        '频率(GHz)': freq_ghz,
                        '幅度(dB)': cursor_magnitude if cursor_magnitude and not str(cursor_magnitude) == 'nan' else 'N/A',
                        '相位(度)': cursor_phase if cursor_phase and not str(cursor_phase) == 'nan' else 'N/A',
                        '信号质量': signal_quality,
                        '目标频率(GHz)': target_freq/1e9
                    })
            except Exception as e:
                print(f"保存CSV文件失败: {e}")
            
            test_counter += 1

            # 等待4秒进行下次测试
            time.sleep(3)
            
    except KeyboardInterrupt:
        print(f"\n\n用户停止测试 (共进行了 {test_counter-1} 次测试)")
        print("=" * 100)
    # 11. 最终状态检查
    print(f"\n最终系统状态:")
    check_error()

# 程序结束
print("\n程序执行完成")